package com.cby.android.olive.ext

import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.os.Parcelable
import android.util.Pair
import android.util.Size
import android.util.SizeF
import java.io.Serializable

/**
 * @description: BundleExt
 *
 * @author ChenBaoyang
 * @date 2021/11/5 09:59
 */

fun bundleOf(vararg pairs: Pair<String, Any?>): Bundle{
    val bundle = Bundle(pairs.size)
    bundle.apply {
        for (element in pairs) {
            when (element.second) {
                null -> putString(element.first, null) // Any nullable type will suffice.

                // Scalars
                is Boolean -> putBoolean(element.first, element.second as Boolean)
                is Byte -> putByte(element.first, element.second as Byte)
                is Char -> putChar(element.first, element.second as Char)
                is Double -> putDouble(element.first, element.second as Double)
                is Float -> putFloat(element.first, element.second as Float)
                is Int -> putInt(element.first, element.second as Int)
                is Long -> putLong(element.first, element.second as Long)
                is Short -> putShort(element.first, element.second as Short)

                // References
                is Bundle -> putBundle(element.first, element.second as Bundle)
                is CharSequence -> putCharSequence(element.first, element.second as CharSequence)
                is Parcelable -> putParcelable(element.first, element.second as Parcelable)

                // Scalar arrays
                is BooleanArray -> putBooleanArray(element.first, element.second as BooleanArray)
                is ByteArray -> putByteArray(element.first, element.second as ByteArray)
                is CharArray -> putCharArray(element.first, element.second as CharArray)
                is DoubleArray -> putDoubleArray(element.first, element.second as DoubleArray)
                is FloatArray -> putFloatArray(element.first, element.second as FloatArray)
                is IntArray -> putIntArray(element.first, element.second as IntArray)
                is LongArray -> putLongArray(element.first, element.second as LongArray)
                is ShortArray -> putShortArray(element.first, element.second as ShortArray)

                // Reference arrays
                is Array<*> -> {
                    val componentType = element.second!!::class.java.componentType!!
                    @Suppress("UNCHECKED_CAST") // Checked by reflection.
                    when {
                        Parcelable::class.java.isAssignableFrom(componentType) -> {
                            putParcelableArray(element.first, element.second as Array<Parcelable>)
                        }
                        String::class.java.isAssignableFrom(componentType) -> {
                            putStringArray(element.first, element.second as Array<String>)
                        }
                        CharSequence::class.java.isAssignableFrom(componentType) -> {
                            putCharSequenceArray(element.first, element.second as Array<CharSequence>)
                        }
                        Serializable::class.java.isAssignableFrom(componentType) -> {
                            putSerializable(element.first, element.second as Array<*>)
                        }
                        else -> {
                            //val element.secondType = componentType.canonicalName
                            throw IllegalArgumentException(
                                "Illegal element.second array type $element.secondType for element.first \"$element.first\""
                            )
                        }
                    }
                }

                // Last resort. Also we must check this after Array<*> as all arrays are serializable.
                is Serializable -> putSerializable(element.first, element.second as Serializable)

                else -> {
                    if (Build.VERSION.SDK_INT >= 18 && element.second is IBinder) {
                        putBinder(element.first, element.second as IBinder)
                    } else if (Build.VERSION.SDK_INT >= 21 && element.second is Size) {
                        putSize(element.first, element.second as Size)
                    } else if (Build.VERSION.SDK_INT >= 21 && element.second is SizeF) {
                        putSizeF(element.first, element.second as SizeF)
                    } else {
                        //element.secondType = element.second!!.javaClass.canonicalName
                        throw IllegalArgumentException("Illegal element.second type $element.secondType for element.first \"$element.first\"")
                    }
                }
            }
        }
    }
    return bundle
}